<?php

namespace tiglog\datatables;


use Yii;
use yii\base\Widget;
use yii\helpers\ArrayHelper;
use yii\helpers\Html;
use yii\helpers\Inflector;
use yii\helpers\Json;
use yii\base\InvalidConfigException;
use yii\i18n\Formatter;
use tiglog\datatables\DataColumn;

/**
 * 特性
 * @property bool $autoWidth Feature control DataTables' smart column width handling
 * @property bool $deferRender Feature control deferred rendering for additional speed of initialisation.
 * @property bool $info Feature control table information display field
 * @property bool $jQueryUI Use markup and classes for the table to be themed by jQuery UI ThemeRoller.
 * @property bool $lengthChange Feature control the end user's ability to change the paging display length of the table.
 * @property bool $ordering Feature control ordering (sorting) abilities in DataTables.
 * @property bool $paging Enable or disable table pagination.
 * @property bool $processing Feature control the processing indicator.
 * @property bool $scrollX Enable horizontal scrolling
 * @property bool $scrollY Enable vertical scrolling
 * @property bool $searching Feature control search (filtering) abilities
 * @property bool $serverSide Enable server-side filtering, paging and sorting calculations
 * @property bool $stateSave Restore table state on page reload
 * @property array $language
 *
 * 选项
 * @property array $ajax Load data for the table's content from an Ajax source
 * @property array $data Data to use as the display data for the table.
 * @property array $columnDefs Set column definition initialisation properties.
 * @property array $columns Set column specific initialisation properties.
 * @property bool|int|array $deferLoading Delay the loading of server-side data until second draw
 * @property bool $destroy Destroy any existing table matching the selector and replace with the new options.
 * @property int $displayStart Initial paging start point
 * @property string $dom Define the table control elements to appear on the page and in what order
 * @property array $lengthMenu Change the options in the page length `select` list.
 * @property bool $orderCellsTop Control which cell the order event handler will be applied to in a column
 * @property bool $orderClasses Highlight the columns being ordered in the table's body
 * @property array $order Initial order (sort) to apply to the table
 * @property array $orderFixed Ordering to always be applied to the table
 * @property bool $orderMulti Multiple column ordering ability control.
 * @property int $pageLength Change the initial page length (number of rows per page)
 * @property string $pagingType Pagination button display options.
 * @property string|array $renderer Display component renderer types
 * @property bool $retrieve Retrieve an existing DataTables instance
 * @property bool $scrollCollapse Allow the table to reduce in height when a limited number of rows are shown.
 * @property array $search
 * @property array $searchCols Define an initial search for individual columns.
 * @property array $searchDelay Set a throttle frequency for searching
 * @property int $stateDuration Saved state validity duration
 * @property array $stripeClasses Set the zebra stripe class names for the rows in the table.
 * @property int $tabIndex Tab index control for keyboard navigation
 *
 * 回调
 * @property string $createdRow Callback for whenever a TR element is created for the table's body.
 * @property string $drawCallback Function that is called every time DataTables performs a draw.
 * @property string $footerCallback Footer display callback function.
 * @property string $formatNumber Number formatting callback function.
 * @property string $headerCallback Header display callback function.
 * @property string $infoCallback Table summary information display callback.
 * @property string $initComplete Initialisation complete callback.
 * @property string $preDrawCallback Pre-draw callback.
 * @property string $rowCallback Row draw callback.
 * @property string $stateLoadCallback Callback that defines where and how a saved state should be loaded.
 * @property string $stateLoaded State loaded callback.
 * @property string $stateLoadParams State loaded - data manipulation callback
 * @property string $stateSaveCallback Callback that defines how the table state is stored and where.
 * @property string $stateSaveParams State save - data manipulation callback
 */
class DataTable extends Widget
{
    public $options = [];
    public $tableOptions = ["class"=>"table table-striped table-bordered"];
    public $clientOptions = [];

    /**
     * 要直接显示的数据，如果是通过 ajax 来调用数据，则此处不用指定
     */
    public $data = [];

    /**
     * 像 gridview 那样定义 columns
     */
    public $columns = [];

    public function init()
    {
        parent::init();
        if (!isset($this->tableOptions['id'])) {
            $this->tableOptions['id'] = 'datatables_'.$this->getId();
        }
        $langfp = __DIR__ . '/langs/' . Yii::$app->language;
        if (file_exists($langfp)) {
            $this->clientOptions['language'] = json_decode(trim(file_get_contents($langfp)));
        }
    }

    public function run()
    {
        echo Html::beginTag('table', $this->tableOptions);
        echo $this->renderTableHeader();
        $this->initTableData();
        echo Html::endTag('table');
        $this->getView()->registerJs('jQuery("#' . $this->tableOptions['id'] . '").DataTable(' . Json::encode($this->getClientOptions()) . ');');
    }


    /**
     * Returns the options for the datatables view JS widget.
     * @return array the options
     */
    protected function getClientOptions()
    {
        return $this->clientOptions;
    }


    /**
     * 一般都应该有 header
     */
    public function renderTableHeader()
    {
        $row = [];
        foreach ($this->columns as $col) {
            array_push($row, $col->renderHeaderCell());
        }
        return "<thead>\n<tr>\n".implode("\n", $row) . "\n</tr>\n</thead>\n";
    }


    /**
     * 把数据放在 clientOptions 里面
     */
    public function initTableData()
    {
        if ($this->isServerSide()) {
            return;
        }
        $rows = [];
        foreach ($this->data as $model) {
            $row = [];
            foreach ($this->columns as $col) {
                array_push($row, Yii::$app->getFormatter()->format($col->getDataCellValue($model), $col->format));
            }
            array_push($rows, $row);
        }
        $this->clientOptions['data'] = $rows;
    }

    /**
     * 当直接显示数据时，需要提供 $this->data
     */
    public function renderTableBody()
    {
        if ($this->isServerSide()) {
            return 'loading';
        }
        $rows = [];
        foreach ($this->data as $model) {
            $row = [];
            foreach ($this->columns as $col) {
                array_push($row, $col->renderDataCell($model));
            }
            array_push($rows, '<tr><td>' . implode('</td><td>', $row) . "</td></tr>\n");
        }
        return "<tbody>\n" . implode('', $rows) . "</tbody>\n";
    }

    protected function isServerSide()
    {
        return isset($this->clientOptions['serverSide']) and $this->clientOptions['serverSide'];
    }
}
